package cn.song.freight.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;


/**
 * 请求流重复读取过滤器
 * 用于解决HTTP请求体只能读取一次的问题
 *
 * 该过滤器的主要功能：
 * 1. 对于JSON等类型的请求，使用RequestWrapper包装原始请求
 * 2. 使请求体数据可以被多次读取
 * 3. 对于表单类型的请求，直接放行不做处理
 *
 * @author SongRenShuo
 * @date 2025/04/03
 */
@Slf4j
@WebFilter("/*")
@Component
public class ReplaceStreamFilter implements Filter {

    /**
     * 执行过滤器逻辑
     * 根据请求的Content-Type类型决定是否需要包装请求对象
     *
     * @param request  原始的ServletRequest对象
     * @param response ServletResponse对象
     * @param chain    过滤器链
     * @throws IOException      IO异常
     * @throws ServletException Servlet异常
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        try {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            String contentType = httpRequest.getContentType();

            // 处理表单类型的请求
            // 表单请求的参数可以通过request.getParameter()多次获取，不需要特殊处理
            if (contentType != null) {
                if (contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)|| contentType.contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
                    chain.doFilter(request, response);
                    return;
                }
            }

            // 处理JSON等类型的请求
            // 这些请求的请求体只能读取一次，需要使用RequestWrapper进行包装
            // RequestWrapper会将请求体数据保存在内存中，允许多次读取
            ServletRequest requestWrapper = new RequestWrapper(httpRequest);
            chain.doFilter(requestWrapper, response);
        } catch (Exception e) {
            log.error("请求流重复读取过滤器异常", e);
            chain.doFilter(request, response);
        }
    }
}
